package com.kizuki.thread;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;

public class TestSingleton {

    @Test
    public void test1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingleton instance = EnumSingleton.INSTANCE;
        Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class);
        constructor.setAccessible(true);
        // java.lang.IllegalArgumentException: Cannot reflectively create enum objects
        EnumSingleton enumSingle = constructor.newInstance();

        System.out.println("instance " + instance);
        System.out.println("enumSingle " + enumSingle);
    }

    @Test
    public void test2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingleton instance = EnumSingleton.INSTANCE;
        Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        // java.lang.NoSuchMethodException: com.kizuki.thread.EnumSingle.<init>()
        EnumSingleton enumSingle = constructor.newInstance();

        System.out.println("instance " + instance);
        System.out.println("enumSingle " + enumSingle);
    }

    /**
     * 外部类加载时,静态内部类的时候不会加载
     * class com.kizuki.thread.MySingleton
     *
     * SingletonHolder 初始化
     * true
     */
    @Test
    public void test3(){
        System.out.println(MySingleton.class);
        System.out.println();
        TestSingleton instance = MySingleton.getInstance();
        TestSingleton instance1 = MySingleton.getInstance();
        System.out.println(Objects.equals(instance, instance1));
    }

}

/**
 * 饿汉式
 * 线程安全
 * 上来就直接创建有可能会浪费资源
 */
class Hungry{
    private Hungry() {
    }

    private static final Hungry HUNGRY = new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }
}

/**
 * 懒汉式
 * 并发线程不安全
 */
class LasyMan {
    private LasyMan() {
    }

    private static LasyMan lasyMan;

    public static LasyMan getInstance(){
        if (lasyMan == null) {
            lasyMan = new LasyMan();
        }
        return lasyMan;
    }
}

/**
 * 线程安全 推荐
 * 实际上的构造方法是 new EnumSingle(String, int); 而不是new EnumSingle();
 * 但是发射也不能破坏，写在反射的底层
 */
enum EnumSingleton {
    INSTANCE;

    public static EnumSingleton getInstance(){
        return INSTANCE;
    }

}


/**
 * 静态内部类方式
 * 最推荐, 线程安全, 在内存上优于enum
 */
class MySingleton{

    private static class SingletonHolder {
        static {
            System.out.println("SingletonHolder 初始化");
        }
        private static final TestSingleton INSTANCE = new TestSingleton();
    }

    public static final TestSingleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}